#include "msg_to_aliyun_by_acl.h"

#ifdef linux
#include <string>
#endif
#include "acl_cpp/lib_acl.hpp"  
#include "acl_cpp/stdlib/string.hpp"
#include "acl_cpp/stdlib/url_coder.hpp"
#include "code/acl_base64.h"

#include "strchange.h"
#include "pfunc.h"
#include "pfunc_v.h"
#include "conf_app.h"
#include "business_def.h"

#include "Log.h"
//c++ version
#include "HMAC_SHA1.h"
#include "Base64.h"
//c version
#include "HMACSHA1.h"

MsgToAliyun::MsgToAliyun()
{
	init();
}

MsgToAliyun::~MsgToAliyun()
{

}

void MsgToAliyun::init()
{
	BusinessDef* ptr_bdef = BusinessDef::getInstance();
	//本区域描述信息
	pyfree::AreaInfo ainfo = ptr_bdef->getAreaInfo();
	char buf[64] = { 0 };
	sprintf(buf, "%d", ainfo.areaId);
	myArgHttp.areaId = std::string(buf);
	sprintf(buf, "%d", ainfo.areaType);
	myArgHttp.areaType = std::string(buf);
	myArgHttp.areaName = ainfo.areaName;
	myArgHttp.areaDesc = ainfo.areaDesc;
	//短信服务接口访问参数
	pyfree::MsgWaring msgwar = ptr_bdef->getMsgWaring();
	myArgHttp.AccessKeyId		= msgwar.WEAccessKeyId;
	myArgHttp.AccessKeySecret	= msgwar.WEAccessKeySecret;
	myArgHttp.PhoneNumbers		= msgwar.WEPhoneNumbers;
	myArgHttp.SignName			= msgwar.WESignName;
	myArgHttp.TemplateCode		= msgwar.WETemplateCode;
	myArgHttp.startTime			= msgwar.WEStartTime;
	myArgHttp.endTime			= msgwar.WEEndTime;
};

void MsgToAliyun::sendMsg(EventForWaring efw)
{
    char comment_buf[512] = { 0 };
	//内容格式需要和阿里云短信中心服务配置的短信模板一致
    sprintf(comment_buf
        , "{"
        "\"ETime\":\"%s\""
        ",\"ADesc\":\"%s\""
        ",\"EType\":\"%s\""
        ",\"ELevel\":\"%s\""
        ",\"TaskID\":\"%s\""
        ",\"DevID\":\"%s\""
        ",\"PID\":\"%s\""
        ",\"ValDesc\":\"%s\""
        "}"
        , efw.execTime.c_str()
        , myArgHttp.areaDesc.c_str()
        , efw.desc.c_str()
        , efw.levelDesc.c_str()
        , efw.taskDesc.c_str()
        , efw.devDesc.c_str()
        , efw.pDesc.c_str()
        , efw.valDesc.c_str()
    );
    send_msg(std::string(comment_buf));
}

//基于acl库的base64编码
int  b64_encode(const char *ptr,char* out_,int size_)
{
	ACL_VSTRING *str = acl_vstring_alloc(1);

	acl_vstring_base64_encode(str, ptr, (int)strlen(ptr));
	int cpy_size = (int) ACL_VSTRING_LEN(str)>size_?size_:(int) ACL_VSTRING_LEN(str);
	strncpy(out_,acl_vstring_str(str),cpy_size);
	acl_vstring_free(str);
	int ret = (int)strlen(out_);
	Print_NOTICE(">>>encode result:%s,len:%d\n", out_,ret);
	return ret;
}
//基于acl库的base64解码
int b64_decode(const char *ptr, char *out_, int size_)
{
	ACL_VSTRING *str = acl_vstring_alloc(1);
#define DECODE(b,x,l) { \
	if (acl_vstring_base64_decode((b),(x),(l)) == 0) { \
		printf("bad base64 encoded string: %s\r\n", (x)); \
		exit (1); \
	} \
}
	DECODE(str, ptr, (int)strlen(ptr));
	int cpy_size = (int) ACL_VSTRING_LEN(str)>size_?size_:(int) ACL_VSTRING_LEN(str);
	strncpy(out_,acl_vstring_str(str),cpy_size);
	acl_vstring_free(str);
	int ret = (int)strlen(out_);
	Print_NOTICE(">>>decode result:%s,len:%d|\n>>>orignal str: {%s}\n", out_,ret, ptr);
	return ret;
}

bool MsgToAliyun::isMapMsgTime()
{
	return pyfree::isMapTime(myArgHttp.startTime,myArgHttp.endTime);
};

void MsgToAliyun::send_msg(std::string templateParam_)
{
	bool accept_gzip = false;
	// bool send_body = false;

	//acl::log::stdout_open(true);
	acl::string aclurl, acladdr/*,aclContentType*/;
	aclurl.format("http://%s%s", myArgHttp.addr_.c_str(), myArgHttp.path_.c_str());
	//aclurl.format("/");
	acladdr.format("%s:%d", myArgHttp.addr_.c_str(), myArgHttp.port_);
	//acladdr.format("%s", myArgHttp.addr_.c_str());
	//aclContentType.format("application/json; charset=%s", myArgHttp.charset_.c_str());

	acl::http_request req(acladdr);

	acl::http_header& header = req.request_header();
	//
	//header.set_method(acl::HTTP_METHOD_POST);
	header.set_method(acl::HTTP_METHOD_GET);
	//
	//header.set_keep_alive(true);
	header.set_keep_alive(false);

	header.accept_gzip(accept_gzip ? true : false);

	//url
	header.set_url(aclurl);
	//host
	if (header.get_host() == NULL)
	{
		header.set_host(myArgHttp.addr_.c_str());
		CLogger::createInstance()->Log(MsgInfo, ">>>set host: %s\r\n", myArgHttp.addr_.c_str());
	}
	else
	{
		CLogger::createInstance()->Log(MsgInfo, ">>>host: %s\r\n", header.get_host());
	}

	//content_type
	//header.set_content_type(aclContentType);
	//header.set_content_length(1024);
	//
	std::string sortQueryStringTmp = "";
	sortQueryStringTmp.append("GET&").append(pyfree::UrlEncode("/"));
	//签名内容,参数key的字符串排序
	std::string SignNameTmp = myArgHttp.SignName;
#ifdef _DEBUG
	Print_NOTICE("SignNameTmp:%s\r\n", SignNameTmp.c_str());
#endif
	//#ifdef WIN32
	SignNameTmp = ASCII2UTF_8(SignNameTmp);
	//#endif
	//
	myArgHttp.TemplateParam = templateParam_;
#ifdef _DEBUG
	Print_NOTICE("templateParam_:%s\r\n", templateParam_.c_str());
#endif // DEBUG
	//#ifdef  WIN32
	myArgHttp.TemplateParam = ASCII2UTF_8(myArgHttp.TemplateParam);
	//#endif //  WIN32
	//
	std::string  bufNonce = pyfree::getUUID();
	std::string Timestamp = pyfree::getCurrentTimeByFormat("%04d-%02d-%02dT%02d:%02d:%02dZ",false);
	//
	acl::url_coder coder;
	coder.set("AccessKeyId", myArgHttp.AccessKeyId.c_str());
	coder.set("Action", myArgHttp.Action.c_str());
	coder.set("Format", myArgHttp.Format.c_str());
	coder.set("OutId", myArgHttp.OutId.c_str());
	coder.set("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());
	coder.set("RegionId", myArgHttp.RegionId.c_str());
	//
	coder.set("SignName", SignNameTmp.c_str());
	//
	coder.set("SignatureMethod", myArgHttp.SignatureMethod.c_str());
	coder.set("SignatureNonce", bufNonce.c_str());
	coder.set("SignatureVersion", myArgHttp.SignatureVersion.c_str());
	coder.set("TemplateCode", myArgHttp.TemplateCode.c_str());
	//发送内容
	coder.set("TemplateParam", myArgHttp.TemplateParam.c_str());
	coder.set("Timestamp", Timestamp.c_str());
	coder.set("Version", myArgHttp.Version.c_str());
	//
	std::string urlcode = std::string(coder.to_string().c_str());
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "sort args[%d]:\r\n%s\r\n"
		, urlcode.length(),urlcode.c_str());
#endif
	//
	sortQueryStringTmp.append("&").append(pyfree::UrlEncode(urlcode));
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "Signature and UrlEncode[%d]:\r\n%s\r\n"
		, sortQueryStringTmp.length(),sortQueryStringTmp.c_str());
#endif
	//生成签名
	char hmac_buf[256] = { 0 };
	std::string KeySecret_ali = (myArgHttp.AccessKeySecret + "&");
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "KeySecret_ali[%d]:\r\n%s\r\n"
		, static_cast<int>(KeySecret_ali.length()), KeySecret_ali.c_str());
	CLogger::createInstance()->Log(MsgInfo, "sortQueryStringTmp[%d]:\r\n%s\r\n"
		, static_cast<int>(sortQueryStringTmp.length()),sortQueryStringTmp.c_str());
#endif
#ifdef WIN32
	hmac_sha((char*)KeySecret_ali.c_str(), static_cast<int>(KeySecret_ali.length())
		, (char*)sortQueryStringTmp.c_str(), static_cast<int>(sortQueryStringTmp.length()), hmac_buf, 20);
#else
	CHMAC_SHA1 c_hmacsha1;
	c_hmacsha1.HMAC_SHA1((unsigned char*)sortQueryStringTmp.c_str(), static_cast<int>(sortQueryStringTmp.length())
		, (unsigned char*)KeySecret_ali.c_str(), static_cast<int>(KeySecret_ali.length())
		, (unsigned char*)hmac_buf);
#endif
	std::string hmac = std::string(hmac_buf,strlen(hmac_buf));
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "KeySecre+HmacSHA1[%d]:\r\n%s\r\n"
		, static_cast<int>(hmac.length()), hmac.c_str());
#endif
	//
	hmac = pyfree::Encode((const unsigned char*)hmac.c_str(), static_cast<int>(hmac.length()));
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "HmacSHA1+Base64[%d]:\r\n%s\r\n"
		, static_cast<int>(hmac.length()), hmac.c_str());
#endif
	//
	header.add_param("Signature", hmac.c_str());
	//
	header.add_param("AccessKeyId", myArgHttp.AccessKeyId.c_str());
	header.add_param("Action", myArgHttp.Action.c_str());
	header.add_param("Format", myArgHttp.Format.c_str());
	header.add_param("OutId", myArgHttp.OutId.c_str());
	header.add_param("PhoneNumbers", myArgHttp.PhoneNumbers.c_str());
	header.add_param("RegionId", myArgHttp.RegionId.c_str());
	header.add_param("SignName", SignNameTmp.c_str());
	header.add_param("SignatureMethod", myArgHttp.SignatureMethod.c_str());
	header.add_param("SignatureNonce", bufNonce.c_str());
	header.add_param("SignatureVersion", myArgHttp.SignatureVersion.c_str());
	header.add_param("TemplateCode", myArgHttp.TemplateCode.c_str());
	header.add_param("TemplateParam", myArgHttp.TemplateParam.c_str());
	header.add_param("Timestamp", Timestamp.c_str());
	header.add_param("Version", myArgHttp.Version.c_str());
	//
	//entry
	//header.add_entry("Authorization", myArgHttp.authorization.c_str());
	//cookie
	//header.add_cookie("x-cookie-name", "cookie-value");

	bool rc = req.request(NULL, 0);
	// 只所以将 build_request 放在 req.request 后面，是因为
	// req.request 内部可能会修改请求头中的字段
	acl::string hdr;
	header.build_request(hdr);
#ifdef _DEBUG
	CLogger::createInstance()->Log(MsgInfo, "request header:\r\n%s\r\n", hdr.c_str());
#endif
	if (rc == false)
	{
		CLogger::createInstance()->Log(MsgInfo, "send msg to ali_yun request error");
		//break;
		return;
	}

	Print_NOTICE("send request ok!\r\n");

	// 取出 HTTP 响应头的 Content-Type 字段  

	const char* p = req.header_value("Content-Type");
	if (p == NULL || *p == 0)
	{
		CLogger::createInstance()->Log(MsgInfo, "no Content-Type");
		return;
	}
	// 分析 HTTP 响应头的数据类型  
	acl::http_ctype content_type;
	content_type.parse(p);
	//p = NULL;
	// 响应头数据类型的子类型  
	const char* stype = content_type.get_stype();

	bool ret = false;
	if (stype != NULL)
	{
		ret = do_plain(req);
	}
//#ifdef WIN32
	//else if (stricmp(stype, "xml") == 0)
//#else
	//else if (strcasecmp(stype, "xml") == 0)
//#endif
	//	ret = do_xml(req);
//#ifdef WIN32
//	else if (stricmp(stype, "json") == 0)//linux->strcasecmp 
//#else
//	else if (strcasecmp(stype, "json") == 0)//linux->strcasecmp 
//#endif
//		ret = do_json(req);
//	else
//		ret = do_plain(req);
	if (ret == true)
	{
		CLogger::createInstance()->Log(MsgInfo, "success for sending msg to ali_yun!");
	}
	else {
		CLogger::createInstance()->Log(MsgInfo, "fail for sending msg to ali_yun!");
	}
	//stype = NULL;
}

// 处理 text/plain 类型数据  
bool MsgToAliyun::do_plain(acl::http_request& req)
{
	acl::string body;
	if (req.get_body(body/*, to_charset_.c_str()*/) == false)
	{
		CLogger::createInstance()->Log(MsgInfo, "get http body error");
		return false;
	}
#ifdef _DEBUG
	Print_NOTICE("body:\r\n(%s)\r\n", body.c_str());
#endif
	return true;
}

//// 处理 text/xml 类型数据  
//bool MsgToAliyun::do_xml(acl::http_request& req)
//{
//	acl::xml body;
//if (req.get_body(body/*, to_charset_.c_str()*/) == false)
//	{
//CLogger::createInstance()->Log(eTipMessage, "get http body error");
//		return false;
//	}
//	acl::xml_node* node = body.first_node();
//	while (node)
//	{
//		const char* tag = node->tag_name();
//		const char* name = node->attr_value("name");
//		const char* pass = node->attr_value("pass");
//		Print_NOTICE(">>tag: %s, name: %s, pass: %s\r\n",
//			tag ? tag : "null",
//			name ? name : "null",
//			pass ? pass : "null");
//		node = body.next_node();
//	}
//	return true;
//}

// 处理 text/json 类型数据  
bool MsgToAliyun::do_json(acl::http_request& req)
{
	acl::json body;
	if (req.get_body(body/*, to_charset_.c_str()*/) == false)
	{
		CLogger::createInstance()->Log(MsgInfo, "get http body error");
		return false;
	}
	//
	acl::json_node* node = body.first_node();
	while (node)
	{
		if (node->tag_name())
		{
			std::string tagStr = std::string(node->tag_name());
			if ("title" == tagStr) 
			{
				std::string valStr = std::string(node->get_text());
				valStr = UTF_82ASCII(valStr);
				printf("tag: %s", node->tag_name());
				if (!valStr.empty())
				{
					printf(", value: %s\r\n", valStr.c_str());
				}
				else
				{
					printf("\r\n");
				}
			}
		}
		node = body.next_node();
	}
	return true;
}